import numpy as np


def numerical_gradient_2d(f, X):
    if X.ndim == 1:#如果是一维数组，按照numerical_gradient方式处理即可
        return numerical_gradient(f, X)
    else:#如果是多维数组
        grad = np.zeros_like(X)#创建一个和X形状相同的全为0的梯度数组

        for idx, x in enumerate(X):#取出X中的每一行的索引（idx），以及对应的整行
            grad[idx] = numerical_gradient(f, x)

        return grad


def numerical_gradient(f,x):#数值微分,计算梯度
    h = 1e-4
    grad = np.zeros_like(x)#生成和x形状一样的全0数组
    for idx in range(x.size): #每一次算完要记得复原，不然影响其他参数的梯度运算
        tmp_val = x[idx]
        x[idx] = tmp_val + h
        fxh1=f(x)
        x[idx] = tmp_val - h
        fxh2=f(x)
        grad[idx] = (fxh1 - fxh2)/(2*h)
        x[idx] = tmp_val
    return grad


def daoshu(f,x):
    h=1e-4
    return (f(x+h)-f(x-h))/(2*h)



def gradient_descent(f, init_x, lr=0.01, step_num=100):
    x = init_x #x的初始值
    for i in range(step_num): #梯度法的重复次数
        grad = numerical_gradient(f, x)#计算当前位置的梯度
        x -= lr * grad#梯度下降
    return x



def function_2(x):
    return np.sum(np.power(x,2))


